/***********************************************************************************
 * 文件名： mcu_onchip_flash.c
 * 作者： 刘言
 * 版本： 1
 * 说明：
 * 		片上FLASH驱动，提供任意地址写入API。
 * 修改记录：
 * 	2020/8/19: 初版。 刘言。
***********************************************************************************/
#include "HC32_LyLib.h"	
#include "mcu_onchip_flash.h"


static void SafeWritePage(const u8 *buff, ofaddr_t addr, ofsize_t length);

/****************************************************************************
* 名    称: u16 Flash_Write(u8 *buff, u16 addr, u16 length)
* 功    能: 向FLASH写入数据
* 入口参数: buff：要写的数据首地址；addr：要写入的Flash地址，length：写入长度
* 出口参数: 0：错误，1：成功
* 说    明: 
* 调用方法: Flash_Write(&obj_buff,0x00001000,sizeof(obj_buff));
****************************************************************************/
bool OcpFlash_Write(const u8 *dat, ofaddr_t addr, ofsize_t length)
{
    u16 addrDiff;
	
	if(length == 0) return true;    
	if(length + addr - FLASH_BASE > FLASH_SIZE) return false;    // 错误
		
    addrDiff = FLASH_PAGE_SIZE - (addr % FLASH_PAGE_SIZE);  // 本页剩余空间
    if(addrDiff < length)    // 剩余空间装不下所有的数据（超出了一页）,写本页剩余空间
    {
        SafeWritePage(dat, addr, addrDiff);
        dat += addrDiff;
        addr += addrDiff;
        length -= addrDiff;
    }
    while(length > FLASH_PAGE_SIZE) //剩余长度大于页大小
    {
        FLASH_WritePage(dat, addr);  //写入一整页
        dat += FLASH_PAGE_SIZE;
        addr += FLASH_PAGE_SIZE;
        length -= FLASH_PAGE_SIZE;
    }
    if(length > 0) SafeWritePage(dat, addr, length);   // 写入最后不足一页长度的数据
            
    FLASH_Lock();

    return true;
}




/****************************************************************************
* 功    能: 使用 读改写 方法，安全的（不破坏数据）向1个页写入部分数据
* 入口参数: buff:要写入的数据 addr:写入地址, length:写入数据长度（字节数）
* 出口参数: 
* 说    明: 需保证写入数据在同一页内
* 调用方法: 
****************************************************************************/
static void SafeWritePage(const u8 *buff, ofaddr_t addr, ofsize_t length)
{
	ofaddr_t addrPage;  // 页首地址
    u16 addrDiff;       // 页内偏移地址
	u16 i;
	u8 mFlashBuff[FLASH_PAGE_SIZE];     // 写入缓存
	
	addrPage = (addr/FLASH_PAGE_SIZE)*FLASH_PAGE_SIZE;
	addrDiff = addr % FLASH_PAGE_SIZE;
	// 读取整页原数据
	for(i = 0; i < FLASH_PAGE_SIZE; i++)
	{
        mFlashBuff[i] = *((u8 *)addrPage + i);
	}
	// 修改需要写的数据
	for(i = 0; i < length; i++)
	{
        mFlashBuff[addrDiff + i] = buff[i];
	}
    //写入新的一整页数据
    FLASH_WritePage(mFlashBuff, addrPage);
}






